<?php

namespace common\Service;

use Yii;
use common\Service\Service;
use yii\helpers\ArrayHelper;

class RedisService extends Service
{
    /**
     * @desc 设置redis hash数据
     * @param string $redisKey
     * @param array $table
     * @return bool
     */
    public static  function setHash($redisKey = '',$table = []){
        if(empty($redisKey) || empty($table)) return false;
        foreach ($table as $key => $value){
            Yii::$app->redis->HSet($redisKey,$key,trim($value));
        }
    }

    /**
     * @desc 读取redis Hash数据
     * @param string $redisKey
     * @param array $fields
     * @return array
     */
    public static function getHash($redisKey = '',$fields = []){
        $data = $rs =  [];
        if(empty($fields)){
            $data = Yii::$app->redis->HGetall(trim($redisKey));

            $count = count($data);
            for($i = 0 ; $i < $count ; $i++){
                if($i % 2 != 0){
                    $rs[$data[$i - 1]] = $data[$i];
                }
            }
        }else{
            $fieldCount = count($fields);
            for($i = 0 ; $i < $fieldCount ; $i++){
                $rs[$fields[$i]] = Yii::$app->redis->HGet($redisKey,$fields[$i]);
            }
        }

        $emptyFieldNum = 0;
        foreach($rs as $val){
            empty($val) && $emptyFieldNum++;
        }
        $emptyFieldNum == count($rs) && $rs = [];


        return $rs;
    }

    /**
     * @desc 分页获取redis数据
     * @param string $redisKey
     * @param int $currentPage
     * @param int $perPage
     * @param string $type
     * @param string $sort
     * @return mixed
     */
    public static function pageData($redisKey = '',$currentPage = 1, $perPage = 10,$type = 'list' ,$sort = 'desc'){
        $pagination['currentPage'] = $currentPage;
        $pagination['perPage'] = $perPage;
        $pagination['totalPage'] = $pagination['totalCount'] = 0;

        $rs['data'] = [];
        $redis = Yii::$app->redis;
        if(strtolower($type) == 'list'){
            $pagination['totalCount'] = (int)$redis->Llen($redisKey);
            $pagination['totalPage'] = ceil($pagination['totalCount'] / $perPage);

            $start = ($currentPage - 1) * $perPage;
            $end = $currentPage * $perPage - 1;
            $rs['data'] = $redis->LRange($redisKey,$start,$end);
        }else if(strtolower($type) == 'zset'){
            $pagination['totalCount'] = $redis->ZCard($redisKey);
            $pagination['totalPage'] = ceil($pagination['totalCount'] / $perPage);

            $start = ($currentPage - 1) * $perPage;
            $end = $currentPage * $perPage - 1;
            if(strtolower($sort) == 'desc'){
                $rs['data'] = $redis->ZRevrange($redisKey,$start,$end);
            }else{
                $rs['data'] = $redis->zRange($redisKey, $start, $end);
            }
        }
        $rs['pagination'] = $pagination;

        return $rs;
    }


    public static function zRange($redisKey = '',$start = 0,$end = -1,$withScores = true,$sort = SORT_DESC){
        $data = [];
        if($withScores){
            $rs = [];
            $data = Yii::$app->redis->ZRange($redisKey,$start,$end,'WITHSCORES');
            if($data){
                $count = count($data);
                for($i = 0 ; $i < $count ; $i++){
                    if($i % 2 != 0){
                        $rs[$data[$i - 1]] = $data[$i];
                    }
                }
                array_multisort($rs,$sort);
            }
            return $rs;
        }else{
            $data = Yii::$app->redis->ZRange($redisKey,$start,$end);
        }
        return $data;
    }

    /**
     * @desc 获取交集数据 这方法可能会把内存玩死
     * @param array $redisKeys 键值 必须大于一个
     * @param int $expire 缓存时间 默认2个小时
     * @return string
     */
    public static function zInterStore($redisKeys = [],$expire = 2 * 60 * 60){
        if(empty($redisKeys)) return '';

        $keyCount = count($redisKeys);
        //最少需要2个集合才能取交
        if($keyCount < 2) return '';
        //最多只能是5个集合取交
        $keyCount > 5 && $keyCount = 5;

        $destination = 'xjj:'.md5(json_encode($redisKeys)); //xjj=>小JJ 并集 djj=>大JJ
        if((int)Yii::$app->get('redis')->exists($destination) == 1) return $destination; //有缓存直接读取缓存

        $rs = 0;
        //下面是一段神奇的代码，请不要问我为什么要这么写。
        switch($keyCount){
            case 2:
                $rs = Yii::$app->get('redis')->zinterstore($destination,$keyCount,$redisKeys[0],$redisKeys[1]);
                break;
            case 3:
                $rs = Yii::$app->get('redis')->zinterstore($destination,$keyCount,$redisKeys[0],$redisKeys[1],$redisKeys[2]);
                break;
            case 4:
                $rs = Yii::$app->get('redis')->zinterstore($destination,$keyCount,$redisKeys[0],$redisKeys[1],$redisKeys[2],$redisKeys[3]);
                break;
            case 5:
                $rs = Yii::$app->get('redis')->zinterstore($destination,$keyCount,$redisKeys[0],$redisKeys[1],$redisKeys[2],$redisKeys[3],$redisKeys[4]);
                break;
            default:
                break;
        }
        if(intval($rs) === 0) return ''; //交集直接就木有数据 TODO 标记取交集没有结果的$destination 避免重复取交集运算
        Yii::$app->get('redis')->expire($destination,$expire);
        return $destination;
    }

    public static function zUnionStore($redisKeys = [],$expire = 2 * 60 * 60,$weights = 1,$aggregate = 'SUM'){
        if(empty($redisKeys)) return '';

        $keyCount = count($redisKeys);
        //最少需要2个集合才能取
        if($keyCount < 2) return $redisKeys[0];
        //最多只能是7个集合取并 7个键值用于周榜排名
        $keyCount > 7 && $keyCount = 7;

        $destination = 'djj:'.md5(json_encode($redisKeys)); //xjj=>小JJ 并集 djj=>大JJ
        if((int)Yii::$app->get('redis')->exists($destination) == 1) return $destination; //有缓存直接读取缓存

        $rs = 0;
        //下面是一段神奇的代码，请不要问我为什么要这么写。
        switch($keyCount){
            case 2:
                $rs = Yii::$app->get('redis')->zunionstore($destination,$keyCount,$redisKeys[0],$redisKeys[1]);
                break;
            case 3:
                $rs = Yii::$app->get('redis')->zunionstore($destination,$keyCount,$redisKeys[0],$redisKeys[1],$redisKeys[2]);
                break;
            case 4:
                $rs = Yii::$app->get('redis')->zunionstore($destination,$keyCount,$redisKeys[0],$redisKeys[1],$redisKeys[2],$redisKeys[3]);
                break;
            case 5:
                $rs = Yii::$app->get('redis')->zunionstore($destination,$keyCount,$redisKeys[0],$redisKeys[1],$redisKeys[2],$redisKeys[3],$redisKeys[4]);
                break;
            default:
                break;
        }
        if(intval($rs) === 0) return ''; //交集直接就木有数据 TODO 标记取交集没有结果的$destination 避免重复取交集运算
        Yii::$app->get('redis')->expire($destination,$expire);
        return $destination;
    }


    public static function getJson($redisKey, $jsonDecode = true){
        $rs = Yii::$app->get('redis')->get($redisKey);

        if($rs && $jsonDecode) $rs = json_decode($rs,true);

        return $rs;
    }

    public static function setJsonString($redisKey,$data = [],$expire = 0){
        if(empty($redisKey) || empty($data))  return;

        Yii::$app->get('redis')->set($redisKey,json_encode($data));

        if($expire > 0) Yii::$app->get('redis')->expire($redisKey,$expire);
    }
}